﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ParametresValeursRefOut1
{
    class PassingRefByVal
    {
        static void Change(int[] pArray) // sans "ref", une copie de la référence sera crée (qui pointe vers le meme objet array)
        {
            // La clé du problème c'est que les méthodes, par défaut, font des copies de ce qu'on leur donne en paramètre, c'est ça ?
            //Du coup même si c'est un Objet passé en paramètre, la méthode en fera une copie et bossera sur la copie de la référence.
            //C'est la raison pour laquelle on peut modifier les champs des objets sans "ref", mais pas la référence à l'objet lui-même, 
            //étant donné que c'est une copie de référence avec laquelle on bosse. 

            pArray[0] = 888;  // This change affects the original element (modification objet via une référence copiée)
            pArray = new int[5] { -3, -1, -2, -3, -4 };   // This change is local. ( référence copiée est affectée par nouveau objet array)
            System.Console.WriteLine("Inside the method, the first element is: {0}", pArray[0]);
        }

        static void Change(int n)
        {
            n = 888;
        }
        static void Change(ref int n)
        {
            n = 888;
        }

        static void ChangeString(string s)
        {
            s.Insert(5, " Auther");
        }

        static void ChangeString(StringBuilder s)
        {
            s.Insert(5, " Auther");
        }

        static void ChangeBuilderString(StringBuilder s)
        {
            s.Insert(5, " Auther");
        }

        static void SwapStrings(ref string s1, ref string s2)
        // The string parameter is passed by reference.
        // Any changes on parameters will affect the original variables.
        {
            string temp = s1;
            s1 = s2;
            s2 = temp;
            System.Console.WriteLine("Inside the method: {0} {1}", s1, s2);
        }

        // La déclaration d'une méthode out est utile lorsque vous souhaitez qu'une méthode retourne plusieurs valeurs.
        //L'exemple suivant utilise out pour retourner trois variables avec un seul appel de méthode.
        //Notez que le troisième argument reçoit la valeur null.Cela permet aux méthodes de retourner des valeurs le cas échéant.
        static void Method(out int i, out string s1, out string s2)
        {
            i = 44;
            s1 = "I've been returned";
            s2 = null;
        }

        class tata
        {
            int[] t = { 1, 65, 6 };
            public void toto()
            {
                NewMethod();

            }
            private void NewMethod()
            {
                for (int i = 0; i < t.Length; i++)
                {
                }
            }
        }

        static void Main()
        {
            int arr0 = 1;
            System.Console.WriteLine("Inside Main, before calling the method, the value is: {0}", arr0);
            Change(arr0);
            System.Console.WriteLine("Inside Main, after calling the method, the value is: {0}", arr0);

            ///////////////////
            int[] arr = { 1, 4, 5 };
            System.Console.WriteLine("\nInside Main, before calling the method, the first element is: {0}", arr[0]);

            Change(arr);
            System.Console.WriteLine("Inside Main, after calling the method, the first element is: {0}", arr[0]);
            System.Console.WriteLine("Inside Main, after calling the method, the size of array: {0}", arr.Length);

            //////////////////////
            string str1 = "John";
            string str2 = "Smith";
            System.Console.WriteLine("\nInside Main, before swapping: {0} {1}", str1, str2);

            SwapStrings(ref str1, ref str2);   // Passing strings by reference
            System.Console.WriteLine("Inside Main, after swapping: {0} {1}", str1, str2);

            /////////////////////////////////
            int value;
            string str11, str21;
            Method(out value, out str11, out str21);
            System.Console.WriteLine("\nOut, after swapping: {0}, {1},{2}", value, str11, str21);
            ///////////////////////////////////
            string s0 = "I'm a string";
            ChangeString(s0);
            Console.WriteLine(s0);
            //Bienque string est de type reference et que ses données sont placée en tas: Un cas exceptionel.
            //C'est le types immuables. Cela signifie qu'une fois que l'instance a été construite, elle ne peut pas être modifiée. 
            //En effet, à chaque fois que vous manipulez une variable de type "string", 
            //un nouvel objet sera créé (sur tas, et bien sur que une référence associée a été crée) et l'objet de base ne sera pas modifié.
            //Cela permet à un type référence de se comporter de façon similaire à un type valeur à certains égards - en particulier
            // C'est pour ca que ca s'appelle un constante (une chaine)

            //Pour remédier à cela, vous pouvez utiliser la classe "StringBuilder" permettant de manipuler
            //des chaînes de caractères sans pour autant créer un nouvel objet à chaque manipulation.
            StringBuilder s1 = new StringBuilder();
            s1.Append("I'm a string");
            ChangeString(s1);
            //ChangeBuilderString(s1);
            Console.WriteLine(s1);

            Console.ReadKey();
        }
    }

}
